package cn.caplike.demo.repository.java.concurrency.thread.join;

/**
 * <h1>Thread.join() 的使用</h1>
 * <p>
 * 在很多情况下，主线程生成并起动了子线程，如果子线程里要进行大量的耗时的运算，
 * 主线程往往将于子线程之前结束，但是如果主线程处理完其他的事务后，需要用到子线程的处理结果，
 * 也就是 主线程需要等待子线程执行完成之后再结束，这个时候就要用到join()方法了
 * </p>
 *
 * <pre>
 * main start. // 主线程起动，因为Thread.sleep(2000)，主线程没有马上结束;
 * [BThread] Thread start.  //线程BThread起动
 * [BThread] Thread loop at 0
 * [BThread] Thread loop at 1
 * [AThread] Thread start. //线程at起动，因为调用了bt.join()，等到bt结束了，此线程才向下执行。
 * [BThread] Thread loop at 2
 * [BThread] Thread loop at 3
 * [BThread] Thread loop at 4
 * [BThread] Thread end.  //线程BThread结束了
 * [AThread] Thread end. // 线程AThread在bt.join();阻塞处起动，向下继续执行的结果
 * main end! // 在sleep两秒后主线程结束，AThread执行的bt.join();并不会影响到主线程。
 * </pre>
 * <p>
 * 如果不加 bt.join
 * <pre>
 * main start.
 * [BThread] Thread start.
 * [BThread] Thread loop at 0
 * [BThread] Thread loop at 1
 * [AThread] Thread start.
 * [AThread] Thread end.
 * main end!
 * [BThread] Thread loop at 2
 * [BThread] Thread loop at 3
 * [BThread] Thread loop at 4
 * [BThread] Thread end.
 * </pre>
 *
 * @author LiKe
 * @version 1.0.0
 * @date 2020-03-01 11:51
 */
public class App {
    public static void main(String[] args) {
        String threadName = Thread.currentThread().getName();
        System.out.println(threadName + " start.");
        BThread bt = new BThread();
        AThread at = new AThread(bt);
        try {
            bt.start();
            Thread.sleep(2000);
            at.start();
            at.join();
        } catch (Exception e) {
            System.out.println("Exception from main");
        }
        System.out.println(threadName + " end!");
    }
}

class BThread extends Thread {
    public BThread() {
        super("[BThread] Thread");
    }

    @Override
    public void run() {
        String threadName = Thread.currentThread().getName();
        System.out.println(threadName + " start.");
        try {
            for (int i = 0; i < 5; i++) {
                System.out.println(threadName + " loop at " + i);
                Thread.sleep(1000);
            }
            System.out.println(threadName + " end.");
        } catch (Exception e) {
            System.out.println("Exception from " + threadName + ".run");
        }
    }
}

class AThread extends Thread {
    BThread bt;

    public AThread(BThread bt) {
        super("[AThread] Thread");
        this.bt = bt;
    }

    @Override
    public void run() {
        String threadName = Thread.currentThread().getName();
        System.out.println(threadName + " start.");
        try {
            bt.join();
            System.out.println(threadName + " end.");
        } catch (Exception e) {
            System.out.println("Exception from " + threadName + ".run");
        }
    }
}

